package com.liqi.framework.aspectj;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.multipart.MultipartFile;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.serializer.ValueFilter;
import com.liqi.common.utils.StringUtils;

import io.swagger.annotations.ApiOperation;

@Aspect
@Component
public class WebLogAspect {
	protected Logger logger = LoggerFactory.getLogger(getClass());

	/*@Pointcut("execution(public * com.liqi.web.controller.openapi..*.*(..))")*/
	@Pointcut("execution(public * com.liqi.web.controller..*.*(..))")
	public void controllerMethod() {
	}

	@Before("controllerMethod()")
	public void before(JoinPoint joinPoint) {
		/*
		 * ServletRequestAttributes attributes = (ServletRequestAttributes)
		 * RequestContextHolder.getRequestAttributes(); if (attributes != null) {
		 * HttpServletRequest request = attributes.getRequest(); String url =
		 * request.getRequestURL().toString(); }
		 */
		MethodSignature ms = (MethodSignature) joinPoint.getSignature();
		Method method = ms.getMethod();
		long tid = Thread.currentThread().getId();
		try {
			// 心跳日志由于每台每隔5分钟发一次，1000台那么日志量比较大，屏蔽心跳日志
			String className = ms.getDeclaringTypeName();
			if (className.indexOf("com.liqi.web.controller.openapi.middleware.HeartBeatController") != -1) {
				return;
			}
			Annotation swaggerAn = method.getAnnotation(ApiOperation.class);
			String apiValue = "";
			if (swaggerAn != null) {
				apiValue = ((ApiOperation) swaggerAn).value();
				logger.info("===> TID:{} => 调用接口: {}，类和方法{}", tid, apiValue, className + "." + method.getName());
			} else {
				logger.info("===> TID:{} => 调用的类和方法{}", tid, className + "." + method.getName());
			}

			if (joinPoint.getArgs().length == 0) {
				return;
			}

			String params = "";
			Annotation getAn = method.getAnnotation(GetMapping.class);
			// get和post入参不一样
			if (getAn != null) {
				String[] argNames = ms.getParameterNames(); // 参数名
				params = argsNameArrayToString(argNames, joinPoint.getArgs());
			} else {
				params = argsArrayToString(joinPoint.getArgs());
			}
			logger.info("===> TID:{} => 调用的参数是：{}", tid, params);
		} catch (Exception e) {
			logger.error("===> TID:{} => 前置通知异常：{}", tid, e);
		}

	}

	/*
	 * @AfterReturning(value = "controllerMethod()", returning = "methodResult")
	 * public void afterReturning(JoinPoint joinPoint, Object methodResult) {
	 * MethodSignature ms = (MethodSignature) joinPoint.getSignature(); Method
	 * method = ms.getMethod(); long tid = Thread.currentThread().getId(); //
	 * 是否需要保存response，参数和值 if (StringUtils.isNotNull(methodResult)) {
	 * logger.info("===> TID:{} => 返回的类和方法{}", tid, ms.getDeclaringTypeName() + "."
	 * + method.getName()); logger.info("===> TID:{} => 返回的参数是：{}", tid,
	 * JSON.toJSONString(methodResult)); } }
	 */

	/**
	 * 环绕
	 * 
	 * @param proceedingJoinPoint
	 * @return
	 * @throws Throwable
	 */
	@Around("controllerMethod()")
	public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
		long startTime = System.currentTimeMillis();
		Object result = proceedingJoinPoint.proceed();

		MethodSignature ms = (MethodSignature) proceedingJoinPoint.getSignature();
		Method method = ms.getMethod();
		long tid = Thread.currentThread().getId();
		try {
			// 心跳日志由于每台每隔5分钟发一次，1000台那么日志量比较大，屏蔽心跳日志
			String className = ms.getDeclaringTypeName();
			if (className.indexOf("com.liqi.web.controller.openapi.middleware.HeartBeatController") != -1) {
				return result;
			}

			// 执行耗时
			logger.info("===> TID:{} => 方法执行花费时间: {} ms", tid, System.currentTimeMillis() - startTime);

			if (StringUtils.isNotNull(result)) {
				logger.info("===> TID:{} => 返回的类和方法{}", tid, ms.getDeclaringTypeName() + "." + method.getName());
				logger.info("===> TID:{} => 返回的参数是：{}", tid,
						JSON.toJSONString(result, SerializerFeature.WriteMapNullValue));
			}
		} catch (Exception e) {
			logger.info("===> TID:{} => 环绕通知异常: {}", tid, e);
		}
		return result;
	}

	/**
	 * 参数名称和值拼装
	 */
	private String argsNameArrayToString(Object[] paramsName, Object[] paramsArray) {
		String params = "";
		if (paramsArray != null && paramsArray.length > 0) {
			StringBuffer sb = new StringBuffer();
			for (int i = 0; i < paramsName.length; i++) {
				sb.append(paramsName[i] + "=" + paramsArray[i]);
				if (i < paramsName.length - 1) {
					sb.append("&");
				}
			}
			params = sb.toString();
		}
		return params.trim();
	}

	/**
	 * 参数拼装
	 */
	private String argsArrayToString(Object[] paramsArray) {
		String params = "";
		if (paramsArray != null && paramsArray.length > 0) {
			for (Object o : paramsArray) {
				if (StringUtils.isNotNull(o) && !isFilterObject(o)) {
					try {
						Object jsonObj = JSON.toJSON(o);
						params += jsonObj.toString() + " ";
					} catch (Exception e) {
                        logger.error("参数拼装异常"+e);
					}

				}
			}
		}
		return params.trim();
	}

	/**
	 * 判断是否需要过滤的对象。
	 * 
	 * @param o 对象信息。
	 * @return 如果是需要过滤的对象，则返回true；否则返回false。
	 */
	@SuppressWarnings("rawtypes")
	public boolean isFilterObject(final Object o) {
		Class<?> clazz = o.getClass();
		if (clazz.isArray() && clazz!=null) {
			return clazz.getComponentType().isAssignableFrom(MultipartFile.class);
		} else if (Collection.class.isAssignableFrom(clazz)) {
			Collection collection = (Collection) o;
			for (Object value : collection) {
				return value instanceof MultipartFile;
			}
		} else if (Map.class.isAssignableFrom(clazz)) {
			Map map = (Map) o;
			for (Object value : map.entrySet()) {
				Map.Entry entry = (Map.Entry) value;
				return entry.getValue() instanceof MultipartFile;
			}
		}
		return o instanceof MultipartFile || o instanceof HttpServletRequest || o instanceof HttpServletResponse
				|| o instanceof BindingResult;
	}

	public static void main(String[] args) {
		String test = "{\"DataType\":\"json\",\"ExceptionMessage\":\"\",\"ErrorServiceId\":null,\"DataList\":[{\"zjlx\":null,\"bdcdwh\":\"340104482009GB00046F00040006\"}]}";
		JSONObject data1 = JSONObject.parseObject(test);
		System.out.println("data1===>" + data1);

		String string22 = JSON.toJSONString(data1);
		// List<Map> data2 = JSONObject.parseArray(string, Map.class);
		System.out.println("string22===>" + string22);

		String string = JSON.toJSONString(data1, SerializerFeature.WriteMapNullValue);
		// List<Map> data2 = JSONObject.parseArray(string, Map.class);
		System.out.println("data2===>" + string);

		/*
		 * String data3 = JSON.toJSONString(data2.get(0), filter);
		 * System.out.println("data3===>"+data3);
		 */

	}

	private static ValueFilter filter = new ValueFilter() {
		@Override
		public Object process(Object obj, String s, Object v) {
			if (v == null)
				return "";
			return v;
		}
	};
	
	/**
     * 拦截异常操作
     * 
     * @param joinPoint 切点
     * @param e 异常
     */
	/*@AfterThrowing(pointcut = "controllerMethod()", throwing = "e")
    public void doAfterThrowing(JoinPoint joinPoint,Exception e)
    {
		handlebefore(joinPoint, e);
    }*/
}
